package com.dews.train.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dews.common.constant.HttpStatus;
import com.dews.common.core.domain.TreeSelect;
import com.dews.common.core.domain.model.LoginUser;
import com.dews.common.core.page.TableDataInfo;
import com.dews.common.exception.ServiceException;
import com.dews.common.utils.SecurityUtils;
import com.dews.information.domain.entity.Subject;
import com.dews.information.service.ISubjectService;
import com.dews.system.domain.SysDept;
import com.dews.system.service.ISysDeptService;
import com.dews.train.convert.TrainingProgramConvert;
import com.dews.train.domain.dto.TrainingProgramDTO;
import com.dews.train.domain.dto.TrainingProgramQueryDTO;
import com.dews.train.domain.entity.TrainingProgram;
import com.dews.train.domain.vo.TrainingProgramVo;
import com.dews.train.mapper.TrainingProgramMapper;
import com.dews.train.service.ITrainingProgramService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 专业培养方案Service业务层处理
 *
 * @author qingfeng
 * @date 2024-11-30
 */
@Service
public class TrainingProgramServiceImpl extends ServiceImpl<TrainingProgramMapper, TrainingProgram> implements ITrainingProgramService {

    private TrainingProgramMapper trainingProgramMapper;
    private ISysDeptService sysDeptService;
    private ISubjectService subjectService;

    @Autowired
    public TrainingProgramServiceImpl(TrainingProgramMapper trainingProgramMapper,
                                      ISysDeptService sysDeptService,
                                      ISubjectService subjectService) {
        this.trainingProgramMapper = trainingProgramMapper;
        this.sysDeptService = sysDeptService;
        this.subjectService = subjectService;
    }

    /**
     * 查询专业培养方案列表
     *
     * @return 专业培养方案
     */
    @Override
    public TableDataInfo selectTrainingProgramList(TrainingProgramQueryDTO trainingProgramQueryDTOVo) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser.getUser().getRoles().stream().anyMatch(e -> e.getRoleKey().equals("subject"))) {
            // 查询专业ID
            Subject subject = subjectService.getOne(
                    Wrappers.lambdaQuery(Subject.class)
                            .eq(Subject::getDirectorId, loginUser.getUserId())
            );
            trainingProgramQueryDTOVo.setSubjectId(subject.getId());
        }
        Page<TrainingProgram> trainingProgramPage = baseMapper.selectPage(
                new Page<TrainingProgram>(trainingProgramQueryDTOVo.getPageNum(), trainingProgramQueryDTOVo.getPageSize()),
                Wrappers.<TrainingProgram>lambdaQuery()
                        .eq(ObjectUtil.isNotNull(trainingProgramQueryDTOVo.getDepId()), TrainingProgram::getDepId, trainingProgramQueryDTOVo.getDepId())
                        .eq(ObjectUtil.isNotNull(trainingProgramQueryDTOVo.getSubjectId()), TrainingProgram::getSubjectId, trainingProgramQueryDTOVo.getSubjectId())
                        .like(StrUtil.isNotBlank(trainingProgramQueryDTOVo.getTrainingProgramTitle()), TrainingProgram::getTrainingProgramTitle, trainingProgramQueryDTOVo.getTrainingProgramTitle())
                        .eq(ObjectUtil.isNotNull(trainingProgramQueryDTOVo.getGrade()), TrainingProgram::getGrade, trainingProgramQueryDTOVo.getGrade())
                        .eq(ObjectUtil.isNotNull(trainingProgramQueryDTOVo.getIsEnable()), TrainingProgram::getIsEnable, trainingProgramQueryDTOVo.getIsEnable())
        );
        if (CollUtil.isEmpty(trainingProgramPage.getRecords())) {
            return TableDataInfo.builder()
                    .code(HttpStatus.SUCCESS)
                    .msg("查询成功")
                    .rows(Collections.emptyList())
                    .total(trainingProgramPage.getTotal())
                    .build();
        }

        Map<Long, String> depMap = sysDeptService.list(
                        Wrappers.<SysDept>lambdaQuery()
                                .in(SysDept::getDeptId, trainingProgramPage.getRecords().stream().map(TrainingProgram::getDepId).collect(Collectors.toSet()))
                ).stream()
                .collect(Collectors.toMap(
                        SysDept::getDeptId,
                        SysDept::getDeptName
                ));
        Map<Integer, String> subjectMap = subjectService.list(
                        Wrappers.<Subject>lambdaQuery()
                                .in(Subject::getId, trainingProgramPage.getRecords().stream().map(TrainingProgram::getSubjectId).collect(Collectors.toSet()))
                ).stream()
                .collect(Collectors.toMap(
                        Subject::getId,
                        Subject::getSubjectName
                ));

        List<TrainingProgramVo> trainingProgramVoList = trainingProgramPage.getRecords()
                .stream()
                .map(trainingProgram -> {
                    TrainingProgramVo trainingProgramVo = TrainingProgramConvert.INSTANCE.convert(trainingProgram);
                    trainingProgramVo.setDepName(depMap.computeIfAbsent(trainingProgram.getDepId(), k -> ""));
                    trainingProgramVo.setSubjectName(subjectMap.getOrDefault(trainingProgram.getSubjectId(), ""));
                    return trainingProgramVo;
                })
                // 找到唯一键  学院 + 专业 + 年级    根据唯一键分组
                .collect(Collectors.groupingBy(trainingProgramVo -> trainingProgramVo.getDepId() + trainingProgramVo.getSubjectId() + trainingProgramVo.getGrade()))
                .values()
                .stream()
                .map(t -> {
                    List<TrainingProgramVo> sortedList = t.stream()
                            .sorted(Comparator.comparing(TrainingProgramVo::getIsEnable).reversed())
                            .collect(Collectors.toList());
                    TrainingProgramVo trainingProgramVo = sortedList.get(0);
                    trainingProgramVo.setChildren(sortedList.subList(1, sortedList.size()));
                    return trainingProgramVo;
                })
                .collect(Collectors.toList());

        return TableDataInfo.builder()
                .code(HttpStatus.SUCCESS)
                .msg("查询成功")
                .rows(trainingProgramVoList)
                .total(trainingProgramPage.getTotal())
                .build();
    }

    /**
     * 新增专业培养方案
     *
     * @return 结果
     */
    @Override
    public int insertTrainingProgram(TrainingProgramDTO trainingProgramDTO) {
        TrainingProgram trainingProgram = TrainingProgramConvert.INSTANCE.convert(trainingProgramDTO);
        checkData(trainingProgramDTO, trainingProgram);
        return baseMapper.insert(trainingProgram);

    }

    /**
     * 修改专业培养方案
     *
     * @return 结果
     */
    @Override
    public int updateTrainingProgram(TrainingProgramDTO trainingProgramDTO) {
        TrainingProgram trainingProgram = TrainingProgramConvert.INSTANCE.convert(trainingProgramDTO);
        checkData(trainingProgramDTO, trainingProgram);
        return baseMapper.updateById(trainingProgram);
    }

    /**
     * 要求：每个学院下的每个专业下的每个年级只能有一个启用的培养方案
     *
     * @param trainingProgramDTO
     * @param trainingProgram
     */
    private void checkData(TrainingProgramDTO trainingProgramDTO, TrainingProgram trainingProgram) {
        if (trainingProgramDTO.getIsEnable() == 1) {
            List<TrainingProgram> trainingProgramList = baseMapper.selectList(
                    Wrappers.<TrainingProgram>lambdaQuery()
                            .ne(ObjectUtil.isNotNull(trainingProgram.getId()), TrainingProgram::getId, trainingProgram.getId())
                            .eq(TrainingProgram::getDepId, trainingProgram.getDepId())
                            .eq(TrainingProgram::getSubjectId, trainingProgram.getSubjectId())
                            .eq(TrainingProgram::getGrade, trainingProgram.getGrade())
                            .eq(TrainingProgram::getIsEnable, 1)
            );
            if (CollUtil.isNotEmpty(trainingProgramList)) {
                throw new ServiceException("该学院专业年级已经存在已启用的专业培养方案，专业培养方案只能存在一个启用的");
            }
        }
    }


    /**
     * 查询专业培养方案
     *
     * @param id 专业培养方案主键
     * @return 专业培养方案
     */
    @Override
    public TrainingProgram selectTrainingProgramById(Integer id) {
        return baseMapper.selectById(id);
    }

    /**
     * 批量删除专业培养方案
     *
     * @param ids 需要删除的专业培养方案主键
     * @return 结果
     */
    @Override
    public int deleteTrainingProgramByIds(List<Integer> ids) {
        return baseMapper.deleteByIds(ids);
    }

    /**
     * 删除专业培养方案信息
     *
     * @param id 专业培养方案主键
     * @return 结果
     */
    @Override
    public int deleteTrainingProgramById(Integer id) {
        return baseMapper.deleteById(id);
    }

    /**
     * 构建专业方案树
     *
     * @return
     */
    @Override
    public List<TreeSelect> getTrainingProgramTree() {
        List<TrainingProgram> trainingProgramList = baseMapper.selectList(Wrappers.<TrainingProgram>lambdaQuery().eq(TrainingProgram::getIsEnable, 1));
        if (CollUtil.isEmpty(trainingProgramList)) {
            return Collections.emptyList();
        }
        Map<Long, String> depMap = sysDeptService.list(
                        Wrappers.<SysDept>lambdaQuery()
                                .in(SysDept::getDeptId, trainingProgramList.stream().map(TrainingProgram::getDepId).collect(Collectors.toSet()))
                ).stream()
                .collect(Collectors.toMap(
                        SysDept::getDeptId,
                        SysDept::getDeptName
                ));
        LoginUser loginUser = SecurityUtils.getLoginUser();
        LambdaQueryWrapper<Subject> queryWrapper = Wrappers.<Subject>lambdaQuery()
                .in(Subject::getId, trainingProgramList.stream().map(TrainingProgram::getSubjectId).collect(Collectors.toSet()));
        if (loginUser.getUser().getRoles().stream().anyMatch(e -> e.getRoleKey().equals("subject"))) {
            queryWrapper.eq(Subject::getDirectorId, loginUser.getUserId());
        }
        Set<Integer> subjectIdSet = subjectService.list(queryWrapper)
                .stream()
                .map(Subject::getId)
                .collect(Collectors.toSet());

        return trainingProgramList.stream()
                .filter(t -> subjectIdSet.contains(t.getSubjectId()))
                .collect(Collectors.groupingBy(TrainingProgram::getDepId))
                .entrySet()
                .stream()
                .map(e -> TreeSelect.builder()
                        .id(e.getKey())
                        .label(depMap.getOrDefault(e.getKey(), ""))
                        .children(
                                e.getValue()
                                        .stream()
                                        .map(t -> TreeSelect.builder()
                                                .id(Long.valueOf(t.getId()))
                                                .label(t.getTrainingProgramTitle())
                                                .build()
                                        )
                                        .collect(Collectors.toList())
                        )
                        .build()
                )
                .collect(Collectors.toList());
    }

}
